梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
AVL 树是一种自平衡二叉搜索树(Self-Balancing Binary Search Tree),由 G.M. Adelson-Velsky 和 E.M. Landis 在 1962 年提出,核心目标是解决普通二叉搜索树(BST)在极端情况下退化成链表(时间复杂度 O (n))的问题。本教程基于链表实现AVL自平衡树,从核心原理、代码结构到实战使用,全面讲解AVL树的原理与实现,功能包含插入、删除、查找、三种遍历、平衡因子计算、旋转、内存释放等核心功能。
| 术语 | 定义 |
|---|---|
| 节点高度 | 叶子节点高度=1,空节点高度=0;非叶子节点高度=max(左子树高度, 右子树高度)+1 |
| 平衡因子(BF) | BF = 左子树高度 - 右子树高度;平衡条件:|BF| ≤ 1 |
| 失衡 | 节点BF的绝对值 > 1,需通过旋转恢复平衡 |
AVL树通过左旋和右旋两种基础操作恢复平衡,四种失衡场景的处理逻辑如下:
| 失衡类型 | 特征 | 旋转策略 |
|---|---|---|
| LL | 左子树的左子树过高 | 对失衡节点右旋 |
| RR | 右子树的右子树过高 | 对失衡节点左旋 |
| LR | 左子树的右子树过高 | 先左旋左子树 → 再右旋失衡节点 |
| RL | 右子树的左子树过高 | 先右旋右子树 → 再左旋失衡节点 |
AVL自平衡树结构是一对多的关系,除了树根之外,每一个节点有唯一的直接前驱(父亲),除了叶子之外,每一个节点有一个或两个直接后继(孩子)。
可以采用顺序存储和链式存储两种形式:
每一个节点有二个域,采用二维数组实现,即数据域data、height节点高度。AVL通过旋转实现平衡,采用二维数组存储时时间复杂度比较高,因此AVL树一般不采用顺序存储结构。
每一个节点有四个域,即数据域data、lchild左节点地址、rchild右节点地址、height节点高度。
提供的代码是模板化的AVL树实现(支持任意类型),采用C++结构体封装,分为头文件(声明)和源文件(实现)两部分,核心结构如下:
| 模块 | 作用 | 关键结构/函数 |
|---|---|---|
| AVL节点结构体 | 存储数据、左节点指针、右节点指针 | AVLNode<T>(模板泛型) |
| AVL树结构体 | 封装所有操作 | LinkedAVLTree<T>(模板类) |
template <typename T>
struct AVLNode {
T data; // 模板化数据域,支持任意类型
AVLNode* left; // 左节点指针指针
AVLNode* right; // 右节点指针
int height; // 节点高度(叶子节点高度为1)
};
int、float、自定义类型等任意类型(需重载比较运算符);分为私有成员(内部实现)和公有成员(对外接口):
template <typename T>
struct LinkedAVLTree{
//------------------------------------------------------------------------------------------------------
// 私有成员
// 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
//------------------------------------------------------------------------------------------------------
private:
//---------------声明私有成员变量---------------
AVLNode<T>* root = nullptr; // 模板类型根节点指针
int level = 0; // 用于跟踪搜索树的层次
int depth = 0; // 用于跟踪搜索树的深度
int qty = 0; // 用于跟踪搜索树的节点数量
//---------------声明私有成员函数---------------
int getHeight(AVLNode<T>* node);// 获取节点高度(空节点高度为0)
void updateHeight(AVLNode<T>* node);// 更新节点高度(基于左右子树高度)
int getBalanceFactor(AVLNode<T>* node);// 计算平衡因子(左子树高度 - 右子树高度)
AVLNode<T>* createAVLNode(const T& val); // 创建新的AVL节点(模板类型) 用const&避免拷贝开销
AVLNode<T>* findMin(AVLNode<T>* node);// 辅助函数:找右子树的最小节点(删除节点时用)
AVLNode<T>* rightRotate(AVLNode<T>* y);// 右旋(处理左左失衡)
AVLNode<T>* leftRotate(AVLNode<T>* x);// 左旋(处理右右失衡)
AVLNode<T>* insertNode(AVLNode<T>* node, const T& val);// 插入节点(递归版本)
AVLNode<T>* insertNodeIter(AVLNode<T>* node, const T& val);// 插入节点(迭代版本)
AVLNode<T>* deleteNode(AVLNode<T>* node, const T& val);// 删除节点(模板类型)
T searchNode(AVLNode<T>* node, const T& val);// 查找节点(模板类型)
void preOrder(AVLNode<T>* node);// 前序遍历(根 → 左 → 右)
void inOrder(AVLNode<T>* node);// 中序遍历(左 → 根 → 右)→ 升序输出
void postOrder(AVLNode<T>* node);// 后序遍历(左 → 右 → 根)
void destroyAVLTree(AVLNode<T>* node);// 销毁整棵树(防止内存泄漏)
//------------------------------------------------------------------------------------------------------
// 公共成员
// 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
//------------------------------------------------------------------------------------------------------
public:
//---------------声明公共成员函数---------------
// 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
LinkedAVLTree() {
root = nullptr; // 初始化为空树
level = depth = qty = 0;
}
int isEmpty();// 判断搜索树是否为空
int isFull();// 判断搜索树是否已满(链表实现永远不满)
int getHeight();// 获取树的高度(根节点高度)
int getBalanceFactor();// 计算根节点的平衡因子
void insertNode(const T& val);// 插入节点(对外接口,模板类型)
void deleteNode(const T& val);// 删除节点(对外接口,模板类型)
T searchNode(const T& val);// 查找节点(对外接口,模板类型)
void preOrder();// 前序遍历(对外接口)
void inOrder();// 中序遍历(对外接口)
void postOrder();// 后序遍历(对外接口)
void destroyTree();// 销毁整棵树(防止内存泄漏)
// 析构函数:自动销毁树,避免内存泄漏
~LinkedAVLTree() {
destroyTree();
}
};
nullptr),所有叶子节点指向NIL。
高度更新是旋转和平衡判断的基础,必须在插入/删除后执行;平衡因子是判断是否失衡的核心依据。
叶子节点高度=1,空节点高度=0;非叶子节点高度=max(左子树高度, 右子树高度)+1
template <typename T>
void LinkedAVLTree::updateHeight(AVLNode* node)
{
if (node == nullptr) return;
int leftH = getHeight(node->left);
int rightH = getHeight(node->right);
node->height = (leftH > rightH ? leftH : rightH) + 1;
}
BF = 左子树高度 - 右子树高度;平衡条件:|BF| ≤ 1
template <typename T>
int LinkedAVLTree::getBalanceFactor(AVLNode* node)
{
return node == nullptr ? 0 : getHeight(node->left) - getHeight(node->right);
}
template <typename T>
int LinkedAVLTree::getHeight(AVLNode* node)
{
return node == nullptr ? 0 : node->height;
}
AVL树通过左旋和右旋两种基础操作恢复平衡,原理是“节点位置互换,保持BST的节点顺序”。
将节点y的左子节点x提升为父节点,y成为x的右子:
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::rightRotate(AVLNode<T>* y)
{
AVLNode<T>* x = y->left; // x是y的左子
AVLNode<T>* B = x->right;
// 执行旋转
x->right = y;
y->left = B;
// 更新高度(先更新y,再更新x,因为x是y的父节点)
updateHeight(y);
updateHeight(x);
return x; // 返回新的根节点
}
将节点x的右子节点y提升为父节点,x成为y的左子:
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::leftRotate(AVLNode<T>* x)
{
AVLNode<T>* y = x->right; // y是x的右子
AVLNode<T>* B = y->left;
// 执行旋转
y->left = x;
x->right = B;
// 更新高度
updateHeight(x);
updateHeight(y);
return y; // 返回新的根节点
}
插入流程:
//插入节点(递归版本)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::insertNode(AVLNode<T>* node, const T& val) {
// 1. 普通BST插入逻辑(适配模板类型比较)
if (node == nullptr) return createAVLNode(val);
if (val < node->data) { // 模板类型需支持<运算符
node->left = insertNode(node->left, val);
} else if (val > node->data) { // 模板类型需支持>运算符
node->right = insertNode(node->right, val);
} else {
// 重复值,AVL树不存储重复值
return node;
}
// 2. 更新当前节点高度
updateHeight(node);
// 3. 计算平衡因子,判断是否失衡
int balance = getBalanceFactor(node);
// 4. 失衡处理(4种情况)
// 情况1:左左失衡(LL)→ 右旋
if (balance > 1 && val < node->left->data) {
return rightRotate(node);
}
// 情况2:右右失衡(RR)→ 左旋
if (balance < -1 && val > node->right->data) {
return leftRotate(node);
}
// 情况3:左右失衡(LR)→ 先左旋左子树,再右旋根
if (balance > 1 && val > node->left->data) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// 情况4:右左失衡(RL)→ 先右旋右子树,再左旋根
if (balance < -1 && val < node->right->data) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
// 未失衡,返回原节点
return node;
}
// 插入节点(迭代版本)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::insertNodeIter(AVLNode<T>* node, const T& val) {
// 处理根节点为空的特殊情况
if (node == nullptr) {
return createAVLNode(val);
}
AVLNode<T>* current = node; // 遍历指针,从根节点开始
AVLNode<T>* parent = nullptr; // 记录当前节点的父节点
// 迭代查找插入位置
while (current != nullptr) {
parent = current; // 更新父节点为当前节点
if (val < current->data) { // 小于当前节点,向左子树查找
current = current->left;
} else if (val > current->data) { // 大于当前节点,向右子树查找
current = current->right;
} else {
// 找到重复值,直接返回原根节点(不插入)
return node;
}
}
// 找到插入位置,创建新节点并挂载到父节点的左/右子树
AVLNode<T>* newNode = createAVLNode(val);
if (val < parent->data) {
parent->left = newNode;
} else {
parent->right = newNode;
}
// 2. 更新当前节点高度
updateHeight(node);
// 3. 计算平衡因子,判断是否失衡
int balance = getBalanceFactor(node);
// 4. 失衡处理(4种情况)
// 情况1:左左失衡(LL)→ 右旋
if (balance > 1 && val < node->left->data) {
return rightRotate(node);
}
// 情况2:右右失衡(RR)→ 左旋
if (balance < -1 && val > node->right->data) {
return leftRotate(node);
}
// 情况3:左右失衡(LR)→ 先左旋左子树,再右旋根
if (balance > 1 && val > node->left->data) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// 情况4:右左失衡(RL)→ 先右旋右子树,再左旋根
if (balance < -1 && val < node->right->data) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
// 未失衡,返回原节点
return node;
}
创建新节点(辅助函数)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::createAVLNode(const T& val)
{
AVLNode<T>* node = new AVLNode<T>(); // 动态分配模板类型节点
if (node == nullptr) {
perror("new failed");
exit(EXIT_FAILURE);
}
node->data = val;
node->left = node->right = nullptr;
node->height = 1; // 叶子节点高度初始化为1
qty++; // 节点数+1
return node;
}
删除流程:
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::deleteNode(AVLNode<T>* node, const T& val) {
// 1. 普通BST删除逻辑
if (node == nullptr) return nullptr;
if (val < node->data) {
node->left = deleteNode(node->left, val);
} else if (val > node->data) {
node->right = deleteNode(node->right, val);
} else {
// 找到要删除的节点,处理3种情况
AVLNode<T>* temp = nullptr;
// 情况1:叶子节点(左右子树都为空)
if (node->left == nullptr && node->right == nullptr) {
temp = node;
node = nullptr; // 置空当前节点,让父节点指向NULL
delete temp; // 释放内存
qty--; // 节点数-1
}
// 情况2:只有一个子树(左空或右空)
else if (node->left == nullptr || node->right == nullptr) {
temp = node->left ? node->left : node->right; // 取非空子树
delete node; // 释放当前节点
node = temp; // 让当前节点指向子树(替代原节点)
qty--; // 节点数-1
}
// 情况3:有两个子树 → 找右子树最小值节点(后继)
else {
temp = findMin(node->right);
node->data = temp->data; // 替换值
node->right = deleteNode(node->right, temp->data); // 删除后继节点
}
}
// 如果树只剩一个节点,直接返回
if (node == nullptr) return nullptr;
// 2. 更新当前节点高度
updateHeight(node);
// 3. 计算平衡因子,判断是否失衡
int balance = getBalanceFactor(node);
// 4. 失衡处理(4种情况)
// 情况1:左左失衡(LL)
if (balance > 1 && getBalanceFactor(node->left) >= 0) {
return rightRotate(node);
}
// 情况2:左右失衡(LR)
if (balance > 1 && getBalanceFactor(node->left) < 0) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// 情况3:右右失衡(RR)
if (balance < -1 && getBalanceFactor(node->right) <= 0) {
return leftRotate(node);
}
// 情况4:右左失衡(RL)
if (balance < -1 && getBalanceFactor(node->right) > 0) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
// 未失衡,返回原节点
return node;
}
找右子树的最小节点(findMin)辅助函数
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::findMin(AVLNode<T>* node)
{
while (node->left != nullptr) node = node->left;
return node;
}
AVL树遍历继承BST的遍历特性:
// 前序遍历(根 → 左 → 右)
template <typename T>
void LinkedAVLTree<T>::preOrder(AVLNode<T>* node) {
if (node == nullptr) return;
// 模板类型需支持<<运算符(或自定义打印逻辑)
std::cout << node->data << " (H: " << node->height << ", BF: " << getBalanceFactor(node) << ") ";
preOrder(node->left);
preOrder(node->right);
}
// 中序遍历(左→根→右)
template <typename T>
void LinkedAVLTree<T>::inOrder(AVLNode<T>* node) {
if (node == nullptr) return;
inOrder(node->left);
std::cout << node->data << " (H: " << node->height << ", BF: " << getBalanceFactor(node) << ") ";
inOrder(node->right);
}
// 后序遍历(左 → 右 → 根)
template <typename T>
void LinkedAVLTree::postOrder(AVLNode* node) {
if (node == nullptr) return;
postOrder(node->left);
postOrder(node->right);
std::cout << node->data << " (H: " << node->height << ", BF: " << getBalanceFactor(node) << ") ";
}
#include "LinkedAVLTree.h"
#include <iostream>
#include "LinkedAVLTree.h"
int main() {
// 1. 创建红黑树对象
LinkedAVLTree<int> avl;
// 2. 插入节点
avl.insertNode(10);
avl.insertNode(20);
avl.insertNode(5);
avl.insertNode(30);
// 3. 中序遍历(升序输出)
std::cout << "中序遍历结果:" << std::endl;
avl.inOrder();
// 4. 查找节点
if (rbt.searchNode(20)) {
std::cout << "找到节点20" << std::endl;
}
// 5. 删除节点
avl.deleteNode(10);
std::cout << "删除10后中序遍历:" << std::endl;
rbt.inOrder();
// 6. 销毁树
avl.destroyTree();
return 0;
}
需先定义Student类,并重载比较运算符(<、==):
// Student类定义(Entitys.h)
#include <string>
#include "Entitys.h"
#include "LinkedAVLTree.h"
// 使用示例
int main() {
LinkedAVLTree<Student> studentAvl;
// 插入学生节点
studentAvl.insertNode({1001,"Eric", "2012-05-18", "男", "汉", "湖南省湘潭县石潭镇", 400, "石潭傎芙蓉中学", "36","在读"});
studentAvl.insertNode({1002,"Bob", "2012-05-18", "男", "汉", "湖南省湘潭县石潭镇", 400, "石潭傎芙蓉中学", "36","在读"});
studentAvl.insertNode({1003,"Charlie", "2012-05-18", "男", "汉", "湖南省湘潭县石潭镇", 400, "石潭傎芙蓉中学", "36","在读"});
// 中序遍历(按ID升序)
studentAvl.inOrder();
// 删除学生
studentAvl.deleteNode({1003,"", "", "", "", "", 0, "", "",""}); // 仅需ID匹配
return 0;
}
#ifndef ENTITYS_H_INCLUDED
#define ENTITYS_H_INCLUDED
//************************************************************************************************************************************************************************
// 自定义类型
//************************************************************************************************************************************************************************
//========================================================================================================================================================================
// 学生结构体(Student)
//========================================================================================================================================================================
struct Student {
int id;// 学号
std::string name;// 姓名
std::string dob;// 出生日期
std::string sex;// 性别
std::string gender;// 民族
std::string address;// 地址
float score;// 入学总分
std::string school;// 学校
std::string team;// 班级
std::string status;// 状态
bool operator<(const Student& other) const { return id < other.id; }
bool operator>(const Student& other) const { return id > other.id; }
bool operator==(const Student& other) const { return id == other.id; }
bool operator!=(const Student& other) const { return id != other.id; }
friend std::ostream& operator<<(std::ostream& os, const Student& s) {
os << "[" << s.id<< ", " << s.name << ", " << s.dob << ", " << s.sex << ", " << s.gender << ", " << s.address << ", " << s.score<< ", " << s.school<< ", " << s.team<< ", " << s.status << "]";
return os;
}
};
//========================================================================================================================================================================
//
// 学生索引结构体(Student)
//
//========================================================================================================================================================================
struct StudentIndex {
int id;// 学号
int row;// 行号
bool operator<(const StudentIndex& other) const { return id < other.id; }
bool operator>(const StudentIndex& other) const { return id > other.id; }
bool operator==(const StudentIndex& other) const { return id == other.id; }
bool operator!=(const StudentIndex& other) const { return id != other.id; }
friend std::ostream& operator<<(std::ostream& os, const StudentIndex& i) {
os << "[" << i.id << ", " << i.row<< "]";
return os;
}
};
//========================================================================================================================================================================
// 迷宫坐标结构体(Pos)
//========================================================================================================================================================================
struct Pos{
int x; //x坐标
int y; //y坐标
int step; //步数
};
//========================================================================================================================================================================
// 打印任务结构体(PrintTask)
//========================================================================================================================================================================
struct PrintTask{
int taskId; // 任务ID
char content[50]; // 打印内容
};
#endif // ENTITYS_H_INCLUDED
#ifndef LINKEDAVLTREE_H_INCLUDED
#define LINKEDAVLTREE_H_INCLUDED
#include "Entitys.h"
//========================================================================================================================================================================
//
// AVL节点结构体(AVLNode)
//
//========================================================================================================================================================================
template <typename T>
struct AVLNode {
T data; // 模板化数据域,支持任意类型
AVLNode* left; // 左节点指针指针
AVLNode* right; // 右节点指针
int height; // 节点高度(叶子节点高度为1)
};
//========================================================================================================================================================================
//
// AVL自平衡树结构体(LinkedAVLTree)
//
//========================================================================================================================================================================
template <typename T>
struct LinkedAVLTree{
//------------------------------------------------------------------------------------------------------
// 私有成员
// 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
//------------------------------------------------------------------------------------------------------
private:
//---------------声明私有成员变量---------------
AVLNode<T>* root = nullptr; // 模板类型根节点指针
int level = 0; // 用于跟踪搜索树的层次
int depth = 0; // 用于跟踪搜索树的深度
int qty = 0; // 用于跟踪搜索树的节点数量
//---------------声明私有成员函数---------------
int getHeight(AVLNode<T>* node);// 获取节点高度(空节点高度为0)
void updateHeight(AVLNode<T>* node);// 更新节点高度(基于左右子树高度)
int getBalanceFactor(AVLNode<T>* node);// 计算平衡因子(左子树高度 - 右子树高度)
AVLNode<T>* createAVLNode(const T& val); // 创建新的AVL节点(模板类型) 用const&避免拷贝开销
AVLNode<T>* findMin(AVLNode<T>* node);// 辅助函数:找右子树的最小节点(删除节点时用)
AVLNode<T>* rightRotate(AVLNode<T>* y);// 右旋(处理左左失衡)
AVLNode<T>* leftRotate(AVLNode<T>* x);// 左旋(处理右右失衡)
AVLNode<T>* insertNode(AVLNode<T>* node, const T& val);// 插入节点(递归版本)
AVLNode<T>* insertNodeIter(AVLNode<T>* node, const T& val);// 插入节点(迭代版本)
AVLNode<T>* deleteNode(AVLNode<T>* node, const T& val);// 删除节点(模板类型)
T searchNode(AVLNode<T>* node, const T& val);// 查找节点(模板类型)
void preOrder(AVLNode<T>* node);// 前序遍历(根 → 左 → 右)
void inOrder(AVLNode<T>* node);// 中序遍历(左 → 根 → 右)→ 升序输出
void postOrder(AVLNode<T>* node);// 后序遍历(左 → 右 → 根)
void destroyAVLTree(AVLNode<T>* node);// 销毁整棵树(防止内存泄漏)
//------------------------------------------------------------------------------------------------------
// 公共成员
// 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
//------------------------------------------------------------------------------------------------------
public:
//---------------声明公共成员函数---------------
// 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
LinkedAVLTree() {
root = nullptr; // 初始化为空树
level = depth = qty = 0;
}
int isEmpty();// 判断搜索树是否为空
int isFull();// 判断搜索树是否已满(链表实现永远不满)
int getHeight();// 获取树的高度(根节点高度)
int getBalanceFactor();// 计算根节点的平衡因子
void insertNode(const T& val);// 插入节点(对外接口,模板类型)
void deleteNode(const T& val);// 删除节点(对外接口,模板类型)
T searchNode(const T& val);// 查找节点(对外接口,模板类型)
void preOrder();// 前序遍历(对外接口)
void inOrder();// 中序遍历(对外接口)
void postOrder();// 后序遍历(对外接口)
void destroyTree();// 销毁整棵树(防止内存泄漏)
// 析构函数:自动销毁树,避免内存泄漏
~LinkedAVLTree() {
destroyTree();
}
};
#endif // LINKEDAVLTREE_H_INCLUDED
#include <iostream>
#include <cstdlib>
#include "LinkedAVLTree.h"
//---------------实现私有成员函数---------------
// 获取节点高度(空节点高度为0)
template <typename T>
int LinkedAVLTree<T>::getHeight(AVLNode<T>* node)
{
return node == nullptr ? 0 : node->height;
}
// 更新节点高度(基于左右子树高度)
template <typename T>
void LinkedAVLTree<T>::updateHeight(AVLNode<T>* node)
{
if (node == nullptr) return;
int leftH = getHeight(node->left);
int rightH = getHeight(node->right);
node->height = (leftH > rightH ? leftH : rightH) + 1;
}
// 计算平衡因子(左子树高度 - 右子树高度)
template <typename T>
int LinkedAVLTree<T>::getBalanceFactor(AVLNode<T>* node)
{
return node == nullptr ? 0 : getHeight(node->left) - getHeight(node->right);
}
// 创建新的AVL节点(模板类型)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::createAVLNode(const T& val)
{
AVLNode<T>* node = new AVLNode<T>(); // 动态分配模板类型节点
if (node == nullptr) {
perror("new failed");
exit(EXIT_FAILURE);
}
node->data = val;
node->left = node->right = nullptr;
node->height = 1; // 叶子节点高度初始化为1
qty++; // 节点数+1
return node;
}
// 辅助函数:找右子树的最小节点(删除节点时用)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::findMin(AVLNode<T>* node)
{
while (node->left != nullptr) node = node->left;
return node;
}
// ===================== 旋转操作(核心) =====================
// 右旋(处理左左失衡)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::rightRotate(AVLNode<T>* y)
{
AVLNode<T>* x = y->left;
AVLNode<T>* B = x->right;
// 执行旋转
x->right = y;
y->left = B;
// 更新高度(先更新y,再更新x,因为x是y的父节点)
updateHeight(y);
updateHeight(x);
return x; // 返回新的根节点
}
// 左旋(处理右右失衡)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::leftRotate(AVLNode<T>* x)
{
AVLNode<T>* y = x->right; // y是x的右子
AVLNode<T>* B = y->left;
// 执行旋转
y->left = x;
x->right = B;
// 更新高度
updateHeight(x);
updateHeight(y);
return y; // 返回新的根节点
}
// 插入节点(递归版本)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::insertNode(AVLNode<T>* node, const T& val) {
// 1. 普通BST插入逻辑(适配模板类型比较)
if (node == nullptr) return createAVLNode(val);
if (val < node->data) { // 模板类型需支持<运算符
node->left = insertNode(node->left, val);
} else if (val > node->data) { // 模板类型需支持>运算符
node->right = insertNode(node->right, val);
} else {
// 重复值,AVL树不存储重复值
return node;
}
// 2. 更新当前节点高度
updateHeight(node);
// 3. 计算平衡因子,判断是否失衡
int balance = getBalanceFactor(node);
// 4. 失衡处理(4种情况)
// 情况1:左左失衡(LL)→ 右旋
if (balance > 1 && val < node->left->data) {
return rightRotate(node);
}
// 情况2:右右失衡(RR)→ 左旋
if (balance < -1 && val > node->right->data) {
return leftRotate(node);
}
// 情况3:左右失衡(LR)→ 先左旋左子树,再右旋根
if (balance > 1 && val > node->left->data) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// 情况4:右左失衡(RL)→ 先右旋右子树,再左旋根
if (balance < -1 && val < node->right->data) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
// 未失衡,返回原节点
return node;
}
// 插入节点(迭代版本)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::insertNodeIter(AVLNode<T>* node, const T& val) {
// 处理根节点为空的特殊情况
if (node == nullptr) {
return createAVLNode(val);
}
AVLNode<T>* current = node; // 遍历指针,从根节点开始
AVLNode<T>* parent = nullptr; // 记录当前节点的父节点
// 迭代查找插入位置
while (current != nullptr) {
parent = current; // 更新父节点为当前节点
if (val < current->data) { // 小于当前节点,向左子树查找
current = current->left;
} else if (val > current->data) { // 大于当前节点,向右子树查找
current = current->right;
} else {
// 找到重复值,直接返回原根节点(不插入)
return node;
}
}
// 找到插入位置,创建新节点并挂载到父节点的左/右子树
AVLNode<T>* newNode = createAVLNode(val);
if (val < parent->data) {
parent->left = newNode;
} else {
parent->right = newNode;
}
// 2. 更新当前节点高度
updateHeight(node);
// 3. 计算平衡因子,判断是否失衡
int balance = getBalanceFactor(node);
// 4. 失衡处理(4种情况)
// 情况1:左左失衡(LL)→ 右旋
if (balance > 1 && val < node->left->data) {
return rightRotate(node);
}
// 情况2:右右失衡(RR)→ 左旋
if (balance < -1 && val > node->right->data) {
return leftRotate(node);
}
// 情况3:左右失衡(LR)→ 先左旋左子树,再右旋根
if (balance > 1 && val > node->left->data) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// 情况4:右左失衡(RL)→ 先右旋右子树,再左旋根
if (balance < -1 && val < node->right->data) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
// 未失衡,返回原节点
return node;
}
// 删除节点(模板类型)
template <typename T>
AVLNode<T>* LinkedAVLTree<T>::deleteNode(AVLNode<T>* node, const T& val) {
// 1. 普通BST删除逻辑
if (node == nullptr) return nullptr;
if (val < node->data) {
node->left = deleteNode(node->left, val);
} else if (val > node->data) {
node->right = deleteNode(node->right, val);
} else {
// 找到要删除的节点,处理3种情况
AVLNode<T>* temp = nullptr;
// 情况1:叶子节点(左右子树都为空)
if (node->left == nullptr && node->right == nullptr) {
temp = node;
node = nullptr; // 置空当前节点,让父节点指向NULL
delete temp; // 释放内存
qty--; // 节点数-1
}
// 情况2:只有一个子树(左空或右空)
else if (node->left == nullptr || node->right == nullptr) {
temp = node->left ? node->left : node->right; // 取非空子树
delete node; // 释放当前节点
node = temp; // 让当前节点指向子树(替代原节点)
qty--; // 节点数-1
}
// 情况3:有两个子树 → 找右子树最小值节点(后继)
else {
temp = findMin(node->right);
node->data = temp->data; // 替换值
node->right = deleteNode(node->right, temp->data); // 删除后继节点
}
}
// 如果树只剩一个节点,直接返回
if (node == nullptr) return nullptr;
// 2. 更新当前节点高度
updateHeight(node);
// 3. 计算平衡因子,判断是否失衡
int balance = getBalanceFactor(node);
// 4. 失衡处理(4种情况)
// 情况1:左左失衡(LL)
if (balance > 1 && getBalanceFactor(node->left) >= 0) {
return rightRotate(node);
}
// 情况2:左右失衡(LR)
if (balance > 1 && getBalanceFactor(node->left) < 0) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// 情况3:右右失衡(RR)
if (balance < -1 && getBalanceFactor(node->right) <= 0) {
return leftRotate(node);
}
// 情况4:右左失衡(RL)
if (balance < -1 && getBalanceFactor(node->right) > 0) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
// 未失衡,返回原节点
return node;
}
// 查找节点(模板类型)
template <typename T>
T LinkedAVLTree<T>::searchNode(AVLNode<T>* node, const T& val) {
if (node == nullptr) { // 未找到
return T();
}
if (val == node->data) { // 模板类型需支持==运算符
return node->data;
} else if (val < node->data) { // 往左子树找
return searchNode(node->left, val);
} else { // 往右子树找
return searchNode(node->right, val);
}
}
// 前序遍历(根 → 左 → 右)
template <typename T>
void LinkedAVLTree<T>::preOrder(AVLNode<T>* node) {
if (node == nullptr) return;
// 模板类型需支持<<运算符(或自定义打印逻辑)
std::cout << node->data << " (H: " << node->height << ", BF: " << getBalanceFactor(node) << ") ";
preOrder(node->left);
preOrder(node->right);
}
// 中序遍历(左 → 根 → 右)→ 升序输出
template <typename T>
void LinkedAVLTree<T>::inOrder(AVLNode<T>* node) {
if (node == nullptr) return;
inOrder(node->left);
std::cout << node->data << " (H: " << node->height << ", BF: " << getBalanceFactor(node) << ") ";
inOrder(node->right);
}
// 后序遍历(左 → 右 → 根)
template <typename T>
void LinkedAVLTree<T>::postOrder(AVLNode<T>* node) {
if (node == nullptr) return;
postOrder(node->left);
postOrder(node->right);
std::cout << node->data << " (H: " << node->height << ", BF: " << getBalanceFactor(node) << ") ";
}
// 销毁整棵树(防止内存泄漏)
template <typename T>
void LinkedAVLTree<T>::destroyAVLTree(AVLNode<T>* node)
{
if (node == nullptr) return;
destroyAVLTree(node->left);
destroyAVLTree(node->right);
delete node; // 释放模板类型节点
qty--;
}
//---------------实现公共成员函数---------------
// 判断搜索树是否为空
template <typename T>
int LinkedAVLTree<T>::isEmpty()
{
return root == nullptr ? 1 : 0;
}
// 判断搜索树是否已满(链表实现永远不满,返回0)
template <typename T>
int LinkedAVLTree<T>::isFull() {
return 0;
}
// 获取树的高度(根节点高度)
template <typename T>
int LinkedAVLTree<T>::getHeight()
{
return getHeight(root);
}
// 计算根节点的平衡因子
template <typename T>
int LinkedAVLTree<T>::getBalanceFactor()
{
return getBalanceFactor(root);
}
// 插入节点(对外接口)
template <typename T>
void LinkedAVLTree<T>::insertNode(const T& val)
{
root = insertNode(root, val);
}
// 删除节点(对外接口)
template <typename T>
void LinkedAVLTree<T>::deleteNode(const T& val)
{
root = deleteNode(root, val);
}
// 查找节点(对外接口)
template <typename T>
T LinkedAVLTree<T>::searchNode(const T& val)
{
return searchNode(root, val);
}
// 前序遍历(对外接口)
template <typename T>
void LinkedAVLTree<T>::preOrder()
{
preOrder(root);
std::cout << std::endl; // 换行,优化输出
}
// 中序遍历(对外接口)
template <typename T>
void LinkedAVLTree<T>::inOrder()
{
inOrder(root);
std::cout << std::endl; // 换行,优化输出
}
// 后序遍历(对外接口)
template <typename T>
void LinkedAVLTree<T>::postOrder()
{
postOrder(root);
std::cout << std::endl; // 换行,优化输出
}
// 销毁整棵树(防止内存泄漏)
template <typename T>
void LinkedAVLTree<T>::destroyTree()
{
destroyAVLTree(root);
root = nullptr;
printf("\n===== 树内存已全部释放 =====\n");
}
// 显式实例化常用类型(避免链接错误,可选)
template class LinkedRBTree<int>;
template class LinkedRBTree<char>;
template class LinkedRBTree<float>;
template class LinkedBSTree<std::string>;
template class LinkedAVLTree<Student>; // 新增:显式实例化Student类型
template class LinkedAVLTree<StudentIndex>; // 新增:显式实例化StudentIndex类型
#include "LinkedAVLTree.h"
#include <iostream>
#include <string>
int main() {
// ==================== 测试1:int类型AVL自平衡树 ====================
LinkedAVLTree<int> intTree;
int intKeys[] = {10, 20, 30, 15, 25, 5, 8};
int n = sizeof(intKeys)/sizeof(intKeys[0]);
// 插入int节点
std::cout << "=== Insert int keys: ";
for (int i = 0; i < n; i++) {
std::cout << intKeys[i] << " ";
intTree.insertNode(intKeys[i]);
}
std::cout << "===" << std::endl;
intTree.preOrder();
// 查找测试
int target = 31;
if (intTree.searchNode(target)) {
std::cout << "\nFound " << target << " in int tree!" << std::endl;
}
// 删除测试
int deleteKey = 5;
std::cout << "\n=== Delete key: " << deleteKey << " ===" << std::endl;
intTree.deleteNode(deleteKey);
// 前序遍历
intTree.preOrder();
// 销毁树(析构函数自动调用,此处显式调用演示)
intTree.destroyTree();
return 0;
}
模板类型约束:
</>/==运算符(内置类型如int/string默认支持,自定义类型需重载);<<运算符(遍历输出时使用)。内存管理:
destroyTree(),无需手动释放,但手动调用也可;qty),可扩展接口返回节点数。重复值处理:代码中AVL树不存储重复值(插入时直接返回),若需支持重复值,可修改插入逻辑(如按<=/>=处理)。
显式实例化:代码末尾的template class LinkedAVLTree<int>;等显式实例化,避免链接错误,新增类型需补充显式实例化。
AVL树是最经典的自平衡二叉搜索树,核心是通过平衡因子检测失衡,并通过旋转恢复平衡,保证树的高度为log₂n级别,从而优化查找/插入/删除效率。
提供的代码实现了模板化的AVL树,支持任意类型数据,封装了核心操作的私有实现和简洁的公共接口,可直接复用。使用时需注意模板类型的运算符重载,以及内存泄漏问题(代码已通过析构函数处理)。
通过本教程,你可以掌握AVL树的原理、核心操作的实现逻辑,以及实际使用方法,适用于需要高效查找/插入/删除的场景(如数据库索引、缓存系统等)。